﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YArchitech.Revit;

namespace HYFloorPipeModule
{
	public class DefiningFloorPipe
	{
		public string ErrorMsg
		{
			get
			{
				return this.errorMsg;
			}
		}

		public DefiningFloorPipe(UIDocument UIDoc)
		{
			this.uiDoc = UIDoc;
			this.sel = this.uiDoc.Selection;
			this.doc = this.uiDoc.Document;
			this.drawYxFloorPipeData = new DrawYxFloorPipeData();
			this.floorTools = new FloorPipeTools(this.doc);
		}

		public bool MakeGroup()
		{
			bool result;
			try
			{
				this.fpgd = new FloorPipeGroupData();
				IList<Reference> list = this.sel.PickObjects((Autodesk.Revit.UI.Selection.ObjectType)1, new HYDefineModelCurveFilter(), "请框选要定义的盘管线：");
				while (this.JustModelLineBelongToGroup(list))
				{
					YJKMessageBox.Information("已选择的盘管线中有已成组的，请重选！");
					RevitVersionFuncs.ClearSelection(this.sel);
					list = this.sel.PickObjects((Autodesk.Revit.UI.Selection.ObjectType)1, new HYDefineModelCurveFilter(), "请框选要定义的盘管线：");
				}
				ElementSet elementSet = new ElementSet();
				Reference refer = null;
				Reference reference = null;
				this.drawYxFloorPipeData.InType = this.PickModelLine(this.sel, list, "请选择盘管的入口线：", out this.fpgd.PipeInId, out refer);
				this.drawYxFloorPipeData.OutType = this.PickModelLine(this.sel, list, "请选择盘管的出口线：", out this.fpgd.PipeLastId, out reference);
				XYZ groupLinePoint = this.GetGroupLinePoint(refer, this.doc);
				XYZ groupLinePoint2 = this.GetGroupLinePoint(reference, this.doc);
				double dis = groupLinePoint.DistanceTo(groupLinePoint2);
				DefineFloorPipeForm defineFloorPipeForm = new DefineFloorPipeForm();
				if (DialogResult.OK != defineFloorPipeForm.ShowDialog())
				{
					this.errorMsg = "用户取消操作！";
					result = false;
				}
				else
				{
					this.drawYxFloorPipeData.Dis = dis;
					this.drawYxFloorPipeData.PipeDN = defineFloorPipeForm.PipeDN;
					this.drawYxFloorPipeData.PipeMaterial = defineFloorPipeForm.PipeMaterial;
					this.drawYxFloorPipeData.DisRadius = defineFloorPipeForm.Radius / 304.8;
					List<ArcPtPair> arcPoints = null;
					if (this.JustShouldDelandDraw(this.GetListCurveElementNode(refer, reference), ref arcPoints))
					{
						List<Element> list2 = this.ReDrawModelLine(arcPoints);
						this.fpgd.PipesLength = this.CalcPipeLength(list2) / 1000.0;
						this.doc.Delete((from e in list
						select e.ElementId).ToList<ElementId>());
                        IEnumerator<Element> enumerator = (from elem in list2
                                                           where elem != null
                                                           select elem).GetEnumerator();
						{
							while (enumerator.MoveNext())
							{
								Element element = enumerator.Current;
								elementSet.Insert(element);
							}
							goto IL_29C;
						}
					}
					this.fpgd.PipesLength = this.CalcPipeLength(list) / 1000.0;
					foreach (Reference reference2 in from elem in list
					where elem != null
					select elem)
					{
						elementSet.Insert(this.doc.GetElement(reference2));
					}
					IL_29C:
					this.fpgd.drawYxFloorPipeData = this.drawYxFloorPipeData;
					this.doc.Regenerate();
					Autodesk.Revit.DB.Group group = this.doc.CreatYJKGroup(elementSet);
					this.floorTools.SetElementES(group, this.fpgd);
					result = true;
				}
			}
			catch (Autodesk.Revit.Exceptions.OperationCanceledException)
			{
				this.errorMsg = "用户取消操作！";
				result = false;
			}
			catch (Exception ex)
			{
				this.errorMsg = ex.Message;
				result = false;
			}
			return result;
		}

		private XYZ GetGroupLinePoint(Reference refer, Autodesk.Revit.DB.Document doc)
		{
			Curve curve = ((doc.GetElementByRef(refer) as ModelCurve).Location as LocationCurve).Curve;
			XYZ hyendPoint = curve.GetEndPoint(0);
			XYZ hyendPoint2 = curve.GetEndPoint(1);
			if (refer.GlobalPoint.DistanceTo(hyendPoint) >= refer.GlobalPoint.DistanceTo(hyendPoint2))
			{
				return hyendPoint2;
			}
			return hyendPoint;
		}

		private double CalcPipeLength(IList<Reference> elems)
		{
			return (from e in elems
			select this.doc.GetElement(e).get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble() * 304.8).Sum();
		}

		private double CalcPipeLength(IList<Element> elems)
		{
			return (from e in elems
			select e.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble() * 304.8).Sum();
		}

		private GraphicsStyle PickModelLine(Selection sel, IList<Reference> es, string str, out ElementId id, out Reference refer)
		{
			for (;;)
			{
				Reference reference = sel.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, new HYModelLineFilter(), str);
				IEnumerator<Reference> enumerator = es.GetEnumerator();
				{
					while (enumerator.MoveNext())
					{
						if (enumerator.Current.ElementId == reference.ElementId)
						{
							id = reference.ElementId;
							refer = reference;
							return (this.doc.GetElement(reference) as ModelCurve).LineStyle as GraphicsStyle;
						}
					}
				}
				YJKMessageBox.Information("请在框选的盘管线中选！！");
			}
			GraphicsStyle result;
			return result;
		}

		private List<CurveElementNode> GetListCurveElementNode(Reference refer, Reference referEnd)
		{
			List<CurveElementNode> list = new List<CurveElementNode>();
			SearchCurve searchCurve = new SearchCurve(this.doc.GetElement(refer), refer.GlobalPoint, 0.016404199475065617);
			searchCurve.DoSearch();
			for (CurveElementNode curveElementNode = searchCurve.GetListRoot(); curveElementNode != null; curveElementNode = curveElementNode.Next)
			{
				list.Add(curveElementNode);
			}
			if (!list.Last<CurveElementNode>().CurveElement.Id.IntegerValue.Equals(referEnd.ElementId.IntegerValue))
			{
				this.errorMsg = "盘管连接有间断或者有重合部分";
				return null;
			}
			return list;
		}

		private List<Element> GetAllModelLine(List<CurveElementNode> nodes)
		{
			if (nodes == null)
			{
				return null;
			}
			this.lstMPs = new List<MixPair>();
			for (int i = 0; i < nodes.Count; i++)
			{
				bool isin = ((nodes[i].CurveElement as ModelCurve).LineStyle as GraphicsStyle).Name.Equals(this.drawYxFloorPipeData.InType.Name);
				if (nodes[i].CurveElement.GeometryCurve is Line)
				{
					this.lstMPs.Add(new MixPair(nodes[i].PointIn, nodes[i].PointOut, isin));
				}
				else if (nodes[i].CurveElement.GeometryCurve is Arc)
				{
					Arc arc = nodes[i].CurveElement.GeometryCurve as Arc;
					XYZ xyz = 0.5 * (nodes[i].PointIn + nodes[i].PointOut);
					xyz = arc.Center + arc.Radius * (xyz - arc.Center).Normalize();
					this.lstMPs.Add(new MixPair(nodes[i].PointIn, xyz, nodes[i].PointOut, isin));
				}
			}
			this.drawYxFloorPipeData.Dis = this.GetDistance(this.lstMPs);
			List<ArcPtPair> arcs = this.floorTools.MakeArcConnect(this.lstMPs, this.drawYxFloorPipeData.DisRadius);
			this.lstMPs.Last<MixPair>().DoExchange();
			List<Element> list = this.CreatModelLine(this.lstMPs);
			list.AddRange(this.CreatModelLine(arcs));
			return list;
		}

		private List<Element> CreatModelLine(List<MixPair> mps)
		{
			List<Curve> list = new List<Curve>();
			List<Curve> list2 = new List<Curve>();
			foreach (MixPair mixPair in mps)
			{
				if (mixPair.IsIn)
				{
					list.Add(mixPair.CreateCurve());
				}
				else
				{
					list2.Add(mixPair.CreateCurve());
				}
			}
			List<Element> list3 = this.floorTools.CreatModelLine(list, this.drawYxFloorPipeData.InType);
			List<Element> list4 = this.floorTools.CreatModelLine(list2, this.drawYxFloorPipeData.OutType);
			this.fpgd.PipeInId = list3.First<Element>().Id;
			this.fpgd.PipeLastId = ((list4.Count == 0) ? list3.Last<Element>().Id : list4.Last<Element>().Id);
			if (list4.Count != 0)
			{
				return list3.Concat(list4).ToList<Element>();
			}
			return list3;
		}

		private List<Element> CreatModelLine(List<ArcPtPair> arcs)
		{
			this.arcPairIn = new List<Curve>();
			this.arcPairOut = new List<Curve>();
			foreach (ArcPtPair arcPtPair in arcs)
			{
				if (arcPtPair.IsIn)
				{
					this.arcPairIn.Add(arcPtPair.CreateArc());
				}
				else
				{
					this.arcPairOut.Add(arcPtPair.CreateArc());
				}
			}
			List<Element> list = this.floorTools.CreatModelLine(this.arcPairIn, this.drawYxFloorPipeData.InType);
			List<Element> list2 = this.floorTools.CreatModelLine(this.arcPairOut, this.drawYxFloorPipeData.OutType);
			if (list2.Count != 0)
			{
				return list.Concat(list2).ToList<Element>();
			}
			return list;
		}

		private List<Element> DealCurveElement(List<CurveElement> elems)
		{
			for (int i = 0; i < elems.Count; i++)
			{
				elems[i].GeometryCurve = this.lstMPs[i].CreateCurve();
			}
			this.doc.Regenerate();
			return (from e in elems
			select e).ToList<Element>();
		}

		private double GetDistance(List<MixPair> mps)
		{
			double result = 0.0;
			for (int i = 0; i < mps.Count; i++)
			{
				for (int j = mps.Count - 1; j > i; j--)
				{
					if (mps[i].IsParallel(mps[j]))
					{
						return mps[i].DistanceTo(mps[j]);
					}
				}
			}
			return result;
		}

		private bool JustShouldDelandDraw(List<CurveElementNode> nodes, ref List<ArcPtPair> arcPoints)
		{
			if (this.drawYxFloorPipeData.DisRadius == 0.0 || nodes == null)
			{
				return false;
			}
			this.GetMixPairData(nodes);
			arcPoints = this.floorTools.MakeArcConnect(this.lstMPs, this.drawYxFloorPipeData.DisRadius);
			this.lstMPs.Last<MixPair>().DoExchange();
			return arcPoints.Count != 0;
		}

		private void GetMixPairData(List<CurveElementNode> nodes)
		{
			List<MixPair> list = new List<MixPair>();
			for (int i = 0; i < nodes.Count; i++)
			{
				bool isin = ((nodes[i].CurveElement as ModelCurve).LineStyle as GraphicsStyle).Name.Equals(this.drawYxFloorPipeData.InType.Name);
				if (nodes[i].CurveElement.GeometryCurve is Line)
				{
					list.Add(new MixPair(nodes[i].PointIn, nodes[i].PointOut, isin));
				}
				else if (nodes[i].CurveElement.GeometryCurve is Arc)
				{
					Arc arc = nodes[i].CurveElement.GeometryCurve as Arc;
					XYZ xyz = 0.5 * (nodes[i].PointIn + nodes[i].PointOut);
					xyz = arc.Center + arc.Radius * (xyz - arc.Center).Normalize();
					list.Add(new MixPair(nodes[i].PointIn, xyz, nodes[i].PointOut, isin));
				}
			}
			this.lstMPs = this.floorTools.MergeMixPairs(list);
		}

		private List<Element> ReDrawModelLine(List<ArcPtPair> arcPoints)
		{
			List<Element> list = this.CreatModelLine(this.lstMPs);
			list.AddRange(this.CreatModelLine(arcPoints));
			return list;
		}

		private bool JustModelLineBelongToGroup(IList<Reference> references)
		{
			foreach (Reference reference in references)
			{
				ModelCurve modelCurve = this.doc.GetElement(reference) as ModelCurve;
				if (modelCurve.GroupId != null && modelCurve.GroupId.IntegerValue != -1)
				{
					return true;
				}
			}
			return false;
		}

		private UIDocument uiDoc;

		private Selection sel;

		private Document doc;

		private DrawYxFloorPipeData drawYxFloorPipeData;

		private FloorPipeTools floorTools;

		private List<Curve> arcPairIn;

		private List<Curve> arcPairOut;

		private List<MixPair> lstMPs;

		private FloorPipeGroupData fpgd;

		private string errorMsg = string.Empty;
	}
}
